﻿#ifndef __OPCODEDISPATCH_H__
#define __OPCODEDISPATCH_H__

#include <map>
#include <string>
#include <iostream>
#include <unordered_map>
#include <memory>
#include <exception>
#include <functional>
#include "singleton.h"
#include "OpcodeContainer.h"
#include "RetValue.h"


#define BEGINE_OPCODEREG(className) public:\
     static void OpcodeInit() {\
        COPHandleContainer<className> handle;

#define OPCODE_BIND(opcode, funcAddr) OpcodeBind(opcode, funcAddr, #funcAddr)

#define END_OPCODEREG() } private:


class COpcodeDispatch
{
public:

	template<typename F>
	void RegisterOpcodeFunc(const char* pszOpcode, F func, const char* pszFuncName)
	{
		if (m_handlers.find(pszOpcode) != m_handlers.end())
		{
			throw std::invalid_argument(std::string(pszOpcode) + " : this opcode has already exist!");
		}
		m_handlers[pszOpcode] = std::bind(&COpcodeDispatch::Proxy<F>, this, func, std::placeholders::_1, std::placeholders::_2);
	}

	//Rpc分发
	template<typename R, typename...Args>
	RetValue<R> Dispatch(const std::string& strOpcode, Args...args)
	{
		std::ostringstream oss;
		if (m_handlers.find(strOpcode) == m_handlers.end())
		{
			return RetValue<R>(RPC_ERR_NOT_REG, "opcode not exist");
		}
		auto fun = m_handlers[strOpcode];

		std::ostringstream ossArg;
		Serialize(ossArg, std::make_pair(args...));

		std::istringstream iss(ossArg.str());
		fun(iss, oss);

		std::istringstream issRet(oss.str());
		RetValue<R> ret;
		Deserialize(issRet, ret);

		return ret;
	}

protected:
	template<typename F>
	void Proxy(F func, std::istream& iss, std::ostream& oss)
	{
		_Proxy(func, iss, oss);
	}
	//代理
	template<typename R, typename C, typename... Args>
	void _Proxy(R(C::* func)(Args...), std::istream& iss, std::ostream& oss)
	{
		using ArgsType = std::tuple<typename std::decay<Args>::type...>;
		ArgsType tuple;
		Deserialize(iss, tuple);
		C obj;
		RetValue<R>::type ret = CallFunc<R, C>(func, &obj, tuple, std::make_index_sequence<sizeof...(Args)>{});
		Serialize(oss, RetValue<R>(ret));
	}

	//二级代理
	void _Proxy(std::function<void(std::istream&, std::ostream&)> func, std::istream& iss, std::ostream& oss)
	{
		func(iss, oss);
	}

	template<typename R, typename C, typename F, typename Tuple, std::size_t... I>
	typename std::enable_if<std::is_same<R, void>::value, typename RetValue<R>::type >::type
		CallFunc(F func, C* pObj, Tuple& tup, std::index_sequence<I...>)
	{
		(pObj->*func)(std::get<I>(tup) ...);
		return 0;
	}

	template<typename R, typename C, typename F, typename Tuple, std::size_t... I>
	typename std::enable_if<!std::is_same<R, void>::value, typename RetValue<R>::type >::type
		CallFunc(F func, C* pObj, Tuple& tup, std::index_sequence<I...>)
	{
		return std::move((pObj->*func)(std::get<I>(tup) ...));
	}

	template<typename R, typename... Args>
	void _Proxy(R(*func)(Args...), std::istream& iss, std::ostream& oss)
	{
		using ArgsType = std::tuple<typename std::decay<Args>::type...>;
		ArgsType tuple;
		Deserialize(iss, tuple);

		RetValue<R>::type ret = std::move(CallFunc<R>(func, tuple, std::make_index_sequence<sizeof...(Args)>{}));
		Serialize(oss, RetValue<R>(ret));
	}

	template<typename R, typename... Args>
	void _Proxy(std::function<R(Args...)> func, std::istream& iss, std::ostream& oss)
	{
		using ArgsType = std::tuple<typename std::decay<Args>::type...>;
		ArgsType tuple;
		Deserialize(iss, tuple);

		RetValue<R>::type ret = std::move(CallFunc<R>(func, tuple, std::make_index_sequence<sizeof...(Args)>{}));
		Serialize(oss, RetValue<R>(ret));
	}
	
	template<typename R, typename F, typename Tuple, std::size_t... I>
	typename std::enable_if<std::is_same<R, void>::value, typename RetValue<R>::type >::type
		CallFunc(F func, Tuple& tup, std::index_sequence<I...>)
	{
		func(std::get<I>(tup) ...);
		return 0;
	}

	template<typename R, typename F, typename Tuple, std::size_t... I>
	typename std::enable_if<!std::is_same<R, void>::value, typename RetValue<R>::type >::type
		CallFunc(F func, Tuple& tup, std::index_sequence<I...>)
	{
		return std::move(func(std::get<I>(tup) ...));
	}
protected:
	std::unordered_map<std::string, std::function<void(std::istream&, std::ostream&)>> m_handlers;
};




typedef Singleton<COpcodeDispatch> COpcodeDispatchAgent;

template<typename F>
void OpcodeBind(const char* pszOpcode, F f, const char* pszFuncName)
{
	COpcodeDispatchAgent::get_instance().RegisterOpcodeFunc(pszOpcode, f, pszFuncName);
}


template<typename R, typename...Args>
RetValue<R> OpcodeCall(const std::string& strOpcode, Args...args)
{
	return std::move(COpcodeDispatchAgent::get_instance().Dispatch<R>(strOpcode, std::forward<Args>(args)...));
}

//异常信息抛出异常
template<typename R, typename...Args>
R OpcodeCallEx(const std::string& strOpcode, Args...args)
{
	return std::move(COpcodeDispatchAgent::get_instance().Dispatch<R>(strOpcode, std::forward<Args>(args)...).GetVal());
}

template<typename...Args>
void OpcodeCallEx(const std::string& strOpcode, Args...args)
{
	COpcodeDispatchAgent::get_instance().Dispatch<void>(strOpcode, std::forward<Args>(args)...);
}


#endif //__OPCODEDISPATCH_H__